package poker;

public class PokerHandEvaluator {
	//WRITE YOUR IMPLEMENTATION HERE
	//THE METHODS MUST MATCH THE DESCRIPTIONS EXACTLY

	/**
	 * A method that finds two cards that are similar
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasPair(Card[] cards){
		int count = 0;
		int totalOcurrance = 0;
		for(int i = 0; i < cards.length; i++){
			totalOcurrance = duplicatorChecker(cards, cards[i].getValue());
		
			if(totalOcurrance > count || totalOcurrance == count){
				count = totalOcurrance;
			}

			if(count >= 2){//two or more cards value same
				return true;
			}else{
				continue;
			}
		}
		return false;
	}
	
	/**
	 * A method that finds all four suits repeated at least once
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasRainbow(Card[] cards){
		int count = 0;
		for(int i = 0; i < cards.length; i++){
			for(int j = 0; j < cards.length; j++){
				if(i == j){
					continue;
				}
				//when two cards have suit same, add 1 to count
				if(cards[i].getSuit() == cards[j].getSuit()){
					count = count + 1;
				}
			}
		}
		if(count > 2){//more than 2 card suit same
			return false;
		}else{
			return true;
		}
	}
	
	/**
	 * A method that finds two pairs of matching values
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasTwoPair(Card[] cards){
		int count = 0;
		int anotherCount = 0;
		boolean fourOfAKindExists = hasFourOfAKind(cards);
		if(fourOfAKindExists == true){
			return true;
		}
		boolean threeOfAKindExists = hasThreeOfAKind(cards);
		if(threeOfAKindExists == true){
			for(int i = 0; i < cards.length; i++){
				for(int j = i + 1 ; j < cards.length; j++){
					//when cards compared are same in value, add to count
					if(cards[i].getValue()== cards[j].getValue()){
						count++;
					}
				}
			}
		}
		if(count == 4){//count 3 for cards that are three of a kind and count
			           // becomes 4 if another pair found(eg:3,3,3,2,2)
			return true;
		}
		for(int i = 0; i < cards.length; i++){
			for(int j = i+1; j < cards.length; j++){
				if(cards[i].getValue() == cards[j].getValue()){
					anotherCount++;
				}
			}
		}
		if(anotherCount == 2){
			return true;
		}
		return false;
	}
	
	/**
	 * A method that finds three cards with matching values 
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasThreeOfAKind(Card[] cards){
		int count = 0;
		int totalOcurrance = 0;
		for(int i = 0; i < cards.length; i++){
			totalOcurrance = duplicatorChecker(cards, cards[i].getValue());
			//when totalOcurrance greater than count, then give count the value
			//of totalOcurrance
			if(totalOcurrance > count){
				count = totalOcurrance;
			}
		}
		if(count >= 3){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * A method that finds five cards with consecutive odd values
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasOddStraight(Card[] cards){
		//we find possible odd consecutive sets of 5 cards, which can have least
		//value as 1,3 or 5. So we iterate from there and add 2 each time
		for(int i = 1; i <= 5; i=i+2){
			//checking for possible values
			if(hasVal(cards,i)&&hasVal(cards,i+2)&&hasVal(cards,i+4)&&hasVal
					(cards,i+6)&&hasVal(cards,i+8)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * A method that finds five cards with consecutive even values
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasEvenStraight(Card[] cards){
		int k;
		//we find possible even consecutive sets of 5 cards, and see if those
		//are present in our array of cards
		for(int i = 0; i <= 6; i=i+2){
			if(i+8==14){//ace card as 14 here, set to 1
				k=1;
			}else{
				k=i+8;
			}
			//check to see if possible even sets of 5 cards are present in
			//our array
			if(hasVal(cards,i)&&hasVal(cards,i+2)&&hasVal(cards,i+4)&&hasVal
					(cards,i+6)&&hasVal(cards,k)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * A method that tells if the value being passed is present in the array
	 * passed
	 * @param cards
	 * @param val- value to be found in the array
	 * @return true or false
	 */

	private static boolean hasVal(Card[] cards, int val){
		
		for(int i = 0; i < cards.length; i++){
			//checks if value passed is present in the array
			if(cards[i].getValue() == val){
				return true;
			}
		}
		return false;

	}
	
	/**
	 * A method that finds five cards with the same suit
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasFlush(Card[] cards){
		int count = 0;
		int i = 0;
		for(int j = 0; j < cards.length; j++){
			//add one to count each time we have similar suit
			if(cards[i].getSuit() == cards[j].getSuit()){
				count = count + 1;
			}
		}
		if(count == 5){//check if all cards have same suit
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * A method that finds a pair that shares the same value and three other 
	 * cards that share a second value
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasFullHouse(Card[] cards){
		boolean fourOfAkind = hasFourOfAKind(cards);
		//four cards can not be the same value for fullhouse
		if(fourOfAkind == true){
			return false;
		}
		boolean threeOfAKind = hasThreeOfAKind(cards);
		boolean hasTwoPair = hasTwoPair(cards);
		//checks if both hasTwoPair and threOfAKind are true since we need three
		//cards of same value and then two cards of the same value but different
		//than the previous 3 cards
		if(hasTwoPair == true  && threeOfAKind == true){
			return true;
		}else{
			return false;
		}	
	}
	
	/**
	 * A method that finds if four cards have the same value
	 * @param cards
	 * @return true or false
	 */

	public static boolean hasFourOfAKind(Card[] cards){
		int count = 0;
		int totalOcurrance = 0;
		for(int i = 0; i < cards.length; i++){
			totalOcurrance = duplicatorChecker(cards, cards[i].getValue());
			//when totalOcurrance is greater than count, assign totalOcurrance 
			//value to count
			if(totalOcurrance > count){
				count = totalOcurrance;
			}
		}
		//if true, means we have at least 4 cards that are the same value
		if(count >= 4){
			return true;
		}
		return false;
	}
	
	/**
	 * A method that finds five cards that have values that are consecutively
	 * odd or even and has all four suits that repeat at least once
	 * @param cards
	 * @return true or false 
	 */

	public static boolean hasStraightRainbow(Card[] cards){
		boolean checkForRainbow = hasDifferentSuit(cards);
		//when a rainbow is present then next condition is check
		if(checkForRainbow == true){
			boolean oddStraightExists = hasOddStraight(cards);
			boolean evenStraightExists = hasEvenStraight(cards);
			//either an odd or and even straight needs to be present in a
			//straight rainbow
			if(oddStraightExists == true || evenStraightExists == true){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * A method that finds five cards that have the values that are
	 * consecutively even or odd and are all of just one suit
	 * @param cards
	 * @return true or false
	 */


	public static boolean hasStraightFlush(Card[] cards){
		boolean flushexists = hasFlush(cards);
		if(flushexists == true){
			boolean oddStraightExists = hasOddStraight(cards);
			boolean evenStraightExists = hasEvenStraight(cards);
			//either an odd straight or even straight needs to be present for
			//a straight flush
			if(oddStraightExists == true || evenStraightExists == true){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * A method that finds if more than two cards are of the same suit
	 * @param cards
	 * @return true or false
	 */

	private static boolean hasDifferentSuit(Card[] cards){
		int count = 0;
		for(int i = 0; i < cards.length; i++){
			for(int j = 0; j < cards.length; j++){
				if(i == j){//skip if same index
					continue;
				}
				//when two card suits similar, add one to count
				if(cards[i].getSuit() == cards[j].getSuit()){
					count += 1;
				}else{
					continue;
				}
			}
		}
		//when more than two cards have same suit, return false
		if(count > 2){
			return false;
		}else{
			return true;
		}
	}
	
	/**
	 * A method that finds how many times a certain value of a card repeats
	 * @param cards
	 * @param val-value to be found in the array
	 * @return count-number of appearance of a card value
	 */

	private static int duplicatorChecker(Card[] cards, int val){
		int count = 0;
		for(int i = 0; i < cards.length; i++){
			//when card value being searched for in the 
			//array is present, adds one to count
			if(cards[i].getValue() == val){
				count = count + 1;
			}
		}
		return count;
	}
}

